package jprint.base.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author zwz
 * Created on 2020-12-16
 */
public class Strings {

    /**
     * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
     * Unicode character set
     */
    public static final Charset US_ASCII = Charset.forName("US-ASCII");

    /**
     * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
     */
    public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");

    /**
     * Eight-bit UCS Transformation Format，类unix上使用的编码
     */
    public static final Charset UTF_8 = Charset.forName("UTF-8");

    /**
     * GBK编码，windows上使用的编码
     */
    public static final Charset GBK = Charset.forName("GBK");

    public static final String TAB = "\t";
    public static final char TAB_CHAR = '\t';
    public static final String CR = "\r";
    public static final char CR_CHAR = '\r';
    public static final String LF = "\n";
    public static final char LF_CHAR = '\n';
    public static final String CRLF = "\r\n";
    public static final String EMPTY_STRING = "";
    public static final char EMPTY_CHAR = '\0';

    private static final Pattern upperPrefix = Pattern.compile("([A-Z]+)\\S*");
    private static final Pattern lowerPrefix = Pattern.compile("([a-z]+)\\S*");
    private static final Pattern chineseReg = Pattern.compile("[\\u4e00-\\u9fa5]+");

    // read methods
    public static String readAsStringUTF8(InputStream ins) {
        return readAsString(ins, UTF_8);
    }

    public static String readAsString(InputStream ins, Charset charset) {
        byte[] bytes = new byte[512];
        ByteArrayOutputStream out = new ByteArrayOutputStream(512);
        try {
            for (int len; ; ) {
                len = ins.read(bytes);
                if (len < 1) {
                    break;
                }
                out.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return charset == null ? new String(out.toByteArray())
            : new String(out.toByteArray(), charset);
    }
    // ~read methods

    // check and test

    /**
     * str是否是一个可见的字符串
     *
     * @param str 待测试的字符串
     * @return true：str可见；false：str不可见
     */
    public static boolean isVisible(String str) {
        return str != null && str.trim().length() > 0;
    }

    /**
     * str是否是一个不可见的字符串
     *
     * @param str 待测试的字符串
     * @return true：str不可见；false：str可见
     */
    public static boolean isNotVisible(String str) {
        return !isVisible(str);
    }

    /**
     * str是否为null或空白
     *
     * @param str 待测试的字符串
     * @return true：str为null或空白；false：str不为空也不是空白
     */
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.length() == 0;
    }

    /**
     * s1和s2的文本内容是否一样，null 和 "" 认为是一样的
     *
     * @param s1 第一个字符串
     * @param s2 第二个字符串
     * @return true：s1和s2的文本内容一样；false：不一样
     */
    public static boolean isSameText(String s1, String s2) {
        if (isNullOrEmpty(s1)) {
            return isNullOrEmpty(s2);
        }
        return s1.equals(s2);
    }

    /**
     * 判断text是否仅包含中文字符
     *
     * @param text 待检查的文本
     * @return true: 仅包含中文字符；false: 其他情况
     */
    public static boolean isChineseOnly(String text) {
        return isVisible(text) && chineseReg.matcher(text).matches();
    }

    public static boolean isVisibleChar(char ch) {
        switch (ch) {
            case '\0':
            case ' ':
            case '\t':
            case '\r':
            case '\n':
                return false;
        }
        return true;
    }
    // ~check and test

    // convert and cast
    public static String toUtf8(String src) {
        if (isNullOrEmpty(src)) return src;
        System.out.println("system charset: " + Charset.defaultCharset().name());
        return new String(src.getBytes(Strings.UTF_8), Strings.UTF_8);
    }

    /**
     * str的第一个可见字符
     *
     * @param str 待处理的字符串
     * @return '\0'：str中没有可见字符；其他：第一个可见字符
     */
    public static char firstVisibleChar(String str) {
        if (isNullOrEmpty(str) || isNotVisible(str)) {
            return EMPTY_CHAR;
        }
        for (char ch : str.toCharArray()) {
            if (isVisibleChar(ch)) {
                return ch;
            }
        }
        return EMPTY_CHAR;
    }

    /**
     * str的最后一个可见字符
     *
     * @param str 待处理的字符串
     * @return '\0'：str中没有可见字符；其他：最后一个可见字符
     */
    public static char lastVisibleChar(String str) {
        if (isNullOrEmpty(str) || isNotVisible(str)) {
            return EMPTY_CHAR;
        }
        char[] chars = str.toCharArray();
        for (int i = chars.length - 1; i >= 0; i--) {
            char ch = chars[i];
            if (isVisibleChar(ch)) {
                return ch;
            }
        }
        return EMPTY_CHAR;
    }

    public static String firstVisible(String... strings) {
        for (String str : strings) {
            if (isVisible(str)) {
                return str;
            }
        }
        return null;
    }

    public static String formatInt(int i, int length) {
        if (length <= 0) {
            return String.valueOf(i);
        }
        return String.format(Locale.US, "%0" + length + "d", i);
    }

    /**
     * 首字母小写的驼峰式 -&gt; 首字母大写的驼峰式
     *
     * @param str 首字母小写的驼峰式
     * @return 首字母大写的驼峰式
     */
    public static String lowerCamelToUpperCamel(String str) {
        Matcher matcher = lowerPrefix.matcher(str);
        if (matcher.find()) {
            String first = matcher.group(1).toUpperCase();
            if (first.length() == str.length()) {
                return first.substring(0, 1).toUpperCase() + str.substring(1);
            }
            return first.toUpperCase() + str.substring(first.length());
        }
        return str;
    }

    /**
     * 首字母大写的驼峰式 -&gt; 首字母小写的驼峰式
     *
     * @param str 首字母大写的驼峰式
     * @return 首字母小写的驼峰式
     */
    public static String upperCamelToLowerCamel(String str) {
        Matcher matcher = upperPrefix.matcher(str);
        if (matcher.find()) {
            String first = matcher.group(1).toUpperCase();
            if (first.length() == str.length()) {
                return first.substring(0, 1).toLowerCase() + str.substring(1);
            }
            return first.toLowerCase() + str.substring(first.length());
        }
        return str;
    }
    // ~convert and cast

    // join and split
    public static String repeat(String str, int times) {
        if (isNullOrEmpty(str) || times < 2) {
            return str;
        }
        StringBuilder sb = new StringBuilder(str);
        for (int i = 2; i <= times; i++) {
            sb.append(str);
        }
        return sb.toString();
    }

    public static String repeatToAtLeastLength(String str, int minLength) {
        if (isNullOrEmpty(str) || str.length() >= minLength) {
            return str;
        }
        int unitLen = str.length();
        int times = (minLength + unitLen - 1) / unitLen;
        return repeat(str, times);
    }

    public static String join(char delimiter, String... strings) {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (String item : strings) {
            if (first) {
                first = false;
            } else {
                sb.append(delimiter);
            }
            sb.append(item);
        }
        return sb.toString();
    }

    public static String concat(Collection<String> strings) {
        StringBuilder sb = new StringBuilder();
        for (String str : strings) {
            if (str != null) {
                sb.append(str);
            }
        }
        return sb.toString();
    }

    public static String stripChar(String str, char flag) {
        if (isNullOrEmpty(str) || flag == EMPTY_CHAR) {
            return str;
        }
        StringBuilder sb = new StringBuilder();
        for (char ch : str.toCharArray()) {
            if (ch != flag) {
                sb.append(ch);
            }
        }
        return sb.toString();
    }

    public static List<String> split(String str, char delimiter) {
        if (isNullOrEmpty(str)) {
            return Arrays.asList(str);
        }
        StringBuilder sb = new StringBuilder();
        List<String> rtn = new ArrayList<>();
        for (char ch : str.toCharArray()) {
            if (ch == delimiter) {
                if (sb.length() > 0) {
                    rtn.add(sb.toString());
                }
                sb.delete(0, sb.length());
            } else {
                sb.append(ch);
            }
        }
        if (sb.length() > 0) // maybe has last part
        {
            rtn.add(sb.toString());
        }
        return rtn;
    }

    public static String leftPadding(String str, int length, char padding) {
        int len = str.length();
        if (length <= len) {
            return str;
        }
        int add = length - len;
        if (add <= 0) {
            return str;
        }
        StringBuilder wrap = new StringBuilder(str);
        for (int i = 1; i <= add; i++) {
            wrap.insert(0, padding);
        }
        return wrap.toString();
    }

    public static String rightPadding(String str, int length, char padding) {
        int len = str.length();
        if (length <= len) {
            return str;
        }
        int add = length - len;
        if (add <= 0) {
            return str;
        }
        StringBuilder wrap = new StringBuilder(str);
        for (int i = 1; i <= add; i++) {
            wrap.append(padding);
        }
        return wrap.toString();
    }
    // ~join and split
}
